package com.tongji.diy.model.furniturePlacementOptimization
{
	import com.tongji.diy.model.RoomDataVO;
	import com.tongji.diy.model.furniturePlacementOptimization.assembleComplement.Facal;
	import com.tongji.diy.model.furniturePlacementOptimization.assembleComplement.FacalCompound;
	import com.tongji.diy.model.furniturePlacementOptimization.assembleComplement.FurnitureBase;
	import com.tongji.diy.model.furniturePlacementOptimization.assembleComplement.FurnitureBlock;
	import com.tongji.diy.model.furniturePlacementOptimization.assembleComplement.NearBase;
	import com.tongji.diy.model.furniturePlacementOptimization.complementStructs.PerframeIteratorData;
	import com.tongji.diy.utils.OptimizationMath;
	import com.tongji.diy.utils.PolygonMath;
	import com.tongji.diy.utils.RoomParameters;
	
	import flash.geom.Point;
	import flash.geom.Vector3D;

	public class DataAndFunction
	{
		public var _room:RoomDataVO;
		
		public var _block:Vector.<FurnitureBase> = new Vector.<FurnitureBase>;
		public var _furnitureBlock:FurnitureBlock;
		public var _tempBlock:Vector.<FurnitureBase> = new Vector.<FurnitureBase>;
		//保存具有靠墙性要求的家具
		public var _aganistWallList:Vector.<FurnitureBase> = new Vector.<FurnitureBase>;
		
		public var _cost:Number = Infinity;
		
		//以下为分析房间获得的数据
		//家具方向选择表
		public var _orientedSelectionList:Vector.<Number> = new Vector.<Number>;
		//房间边长累加表，用于在墙壁上进行随机摆放时选择墙壁使用
		public var _roomSideLengthList:Vector.<Number> = new Vector.<Number>;
		//房间周长
		public var _roomCircumference:Number = 0;
		//房间内部垂直于墙的方向向量表
		public var _roomWallVerticalOrentationList:Vector.<Point> = new Vector.<Point>;
		//房间顶点向量表，由于原始数据是双向链表，这里进行了修正改为vector进行存储
		public var _roomPoints:Vector.<Point> = new Vector.<Point>;
		//房间顶点随机数列表，对应于房间顶点与周长的关系，求出房间顶点映射到周长上的随机数
		public var _roomRandnums:Vector.<Number> = new Vector.<Number>;
		
		//以下为block中各种object的列表
		public var _facalList:Vector.<FurnitureBase> = new Vector.<FurnitureBase>;
		public var _seatList:Vector.<FurnitureBase> = new Vector.<FurnitureBase>;
		public var _beddingList:Vector.<FurnitureBase> = new Vector.<FurnitureBase>;
		
		//以下两个list虽然类型为NearBase，但是实际存储的元素皆为相对应的beddingNearby,以及seatNearby
		//如此设计目的是在应用collision以及迭代过程中能够统一使用
		public var _beddingNearbyList:Vector.<NearBase> = new Vector.<NearBase>;
		public var _seatNearbyList:Vector.<NearBase> = new Vector.<NearBase>;
		//存储该constructor的所有boundingBox
		public var _boundBoxes:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>;
		
		//判断nearby是不是已经存在
		public var nearbyBoundExist:Boolean = false;
		//标志位，block中是否存在对称家具
		public var symetrySign:Boolean = false;
		//标志位，block中要进行家具遮挡测试
		public var visibleSign:Boolean = false;
		//标志位，block是否有bedding
		public var beddingSign:Boolean = false;
		//标志位，block是否有seat
		public var seatSign:Boolean = false;
		//用于辅助计算symetry的结构
		public var symetryList:Vector.< Vector.<NearBase> > = new Vector.< Vector.<NearBase> >;
		//用于辅助计算visible的结构
		public var visibleList:Vector.<NearBase> = new Vector.<NearBase>;
		
		//test，每帧迭代使用
		public var perFrameData:PerframeIteratorData = new PerframeIteratorData;
		
		//高效三角形矩形碰撞测试
		//private var triangleSign:Vector.<int> = new Vector.<int>;
		//private var lineEquation:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>;
		private var visibleTriangle:Vector.<Point> = new Vector.<Point>;
		
		public function DataAndFunction()
		{
		}
		
		//可见性检测，可见性测试失败返回false
		public function visibleTest():Boolean
		{
			if(!visibleList.length && (!_beddingList.length || !_seatList.length) || !_facalList.length)
				return true;
			var facal:Facal;
			var list:Vector.<FurnitureBase>;
			if(_beddingList.length)
				list = _beddingList;
			else
				list = _seatList;
			if(_facalList[0] is FacalCompound)
			{
				//				if((data._facalList[0] as FacalCompound).containee)
				facal = (_facalList[0] as FacalCompound).containee;
				//				else
				//					facal = (data._facalList[0] as FacalCompound).container;
			}
			else
				facal = _facalList[0] as Facal;
			
			for(var j:int = 0; j < list.length; ++j)
			{
				for(var i:int = 0; i < visibleList.length; ++i)
				{
					var triangle:Vector.<Point> = new Vector.<Point>;
					triangle.push(new Point(list[j].accX, list[j].accY));
					triangle.push(facal.accessibleBox[2], facal.accessibleBox[3]);
					if(PolygonMath.triangleIntersecRectangle(triangle, visibleList[i].accessibleBox))
						return false;
				}
			}
			return true;
		}
		
		//两个furniture的accessiblebox碰撞检测，返回值true说明两者有碰撞
		//该函数将会判断两个accessiblebox以及boundingbox之间的碰撞情况
		public function accessibleBoxCollision(boxA:FurnitureBase, boxB:FurnitureBase):Boolean
		{
			if(boxA.accMaxX < boxB.accMinX || boxA.accMinX > boxB.accMaxX)
				return false
			if(boxA.accMaxY < boxB.accMinY || boxA.accMinY > boxB.accMaxY)
				return false;
			if(PolygonMath.rectangleSeparatingAxisCollisionTest(boxA.accessibleBox, boxB.accessibleBox) != -1)
				return false;
			if(PolygonMath.rectangleSeparatingAxisCollisionTest(boxA.accessibleBox, boxB.boundingBox) != -1 && PolygonMath.rectangleSeparatingAxisCollisionTest(boxA.boundingBox, boxB.accessibleBox) != -1)
				return false;
			return true;
		}
		//准备三角形矩形碰撞
//		public function perpareTriangle(triangle:Vector.<Point>):void
//		{
//			for(var i:int = 0; i < 3; ++i)
//			{
//				var lineV:Vector.<Number> = PolygonMath.buildLineAccrodingTwoPoints(triangle[i],triangle[(i+1)%3]);
//				lineEquation.push(lineV);
//				if(lineV[0] * triangle[(i+2)%3].x + lineV[1] * triangle[(i+2)%3].y + lineV[2] < 0)
//					triangleSign[i] = -1;
//				else
//					triangleSign[i] = 1;
//			}
//		}
		//执行碰撞
//		public function triangleRectangleCollision(rectangle:Vector.<Point>):Boolean
//		{
//			OptimizationMath.assert(lineEquation.length > 0);
//			for(var i:int  = 0; i < rectangle.length; ++i)
//			{
//				for(var j:int = 0; j < lineEquation.length; ++j)
//				{
//					if((lineEquation[j][0]*rectangle[i].x + lineEquation[j][1]*rectangle[i].y + lineEquation[j][2])*triangleSign[j] < 0)
//						return true;						
//				}
//			}
//			return false;
//		}
		
		//该函数是searchLocationWall函数的逆向函数，用于求所给的randNum；
		//返回值为-1，说明当前furniture不在靠墙的位置
		public function reverseRandom(fur:FurnitureBase):Number
		{
			var furLoc:Point = new Point(fur.x + _room.x,fur.y + _room.y);
			for(var i:int = 0; i < _roomPoints.length; ++i)
			{
				if(PolygonMath.equal(PolygonMath.pointToLineSquareDistance(_roomPoints[i],_roomPoints[(i+1)%_roomPoints.length],furLoc),(fur.length/2+1+RoomParameters.wallWidth)*(fur.length/2+1+RoomParameters.wallWidth),0.1))
				{
					break;
				}
			}
			if(i == _roomPoints.length)
				return -1;
			var pedal:Point = PolygonMath.pedal(_roomPoints[i],_roomPoints[(i+1)%_roomPoints.length],furLoc);
			var distance:Number = (pedal.subtract(_roomPoints[i])).length - fur.width / 2;
			OptimizationMath.assert(distance >= 0);
			var ranDistance:Number = distance / ((_roomPoints[i].subtract(_roomPoints[(i+1)%_roomPoints.length])).length - fur.width) * ((_roomPoints[i].subtract(_roomPoints[(i+1)%_roomPoints.length])).length);
			if(i > 0)
			{
				ranDistance += _roomSideLengthList[i - 1];
				return ranDistance/_roomCircumference;
			}
			else
			{
				return ranDistance/_roomCircumference;
			}
		}
		
		//判断包围盒是否在房间内部，如果是在内部则返回true
		public function boundingBoxInRoom(boundingbox:Vector.<Point>, room:RoomDataVO):Boolean
		{
			for(var i:int; i < boundingbox.length; ++i)
			{
				if(!PolygonMath.pointIsInPoly(room.roomPointList.head, boundingbox[i].add(new Point(room.x,room.y))))
				{
					return false;
				}
			}
			return true;
		}
		
		public function noNearBoarderRandNum():Number
		{
			var randNum:Number = Math.random();
			var lowIndex:int = 0;
			var upperIndex:int = _roomRandnums.length;
			
			for(var i:int = 0; i < this._roomRandnums.length; ++i)
			{
				if(_roomRandnums[i] > randNum)
				{
					lowIndex = i;
					break;
				}
			}
			while(Math.abs(randNum - _roomRandnums[lowIndex]) < 0.05 
				|| Math.min(
					Math.abs(randNum - _roomRandnums[(lowIndex - 1 + _roomRandnums.length)%_roomRandnums.length])
					,Math.abs(randNum - 0)) < 0.05)
			{
				randNum = Math.random();
				for(i = 0; i < this._roomRandnums.length; ++i)
				{
					if(_roomRandnums[i] > randNum)
					{
						lowIndex = i;
						break;
					}
				}
			}				
			return randNum;
		}
		
		//返回值为一个vector3D，其xy值为所求家具的坐标值，z值是家具的角度值
		public function searchLocationWall(fur:FurnitureBase, randomNum:Number, furWidth:Number = 0, furLength:Number = 0):Vector3D
		{
			OptimizationMath.assert(randomNum >=0 &&randomNum <= 1)
			if(fur)
			{
				furWidth = fur.width;
				furLength = fur.length;
			}				
			var length:Number = randomNum * _roomCircumference;
			var start:int = Math.floor(length/_roomCircumference);
			var location:int;
			if(_roomSideLengthList[start] < length)
				location = binarySearch(start+1, _roomSideLengthList.length-1,length);
			else if(_roomSideLengthList[start] > length)
				location = binarySearch(0, start,length);
			else
				location = start;
			
			var tempV:Point = _roomPoints[(location+1) % _roomPoints.length].subtract(_roomPoints[location]);
			
			var furnitureLocation:Vector3D = new Vector3D;
			var position:Number;
			if(location != 0)
			{
				var temp:Number = _roomSideLengthList[location] - _roomSideLengthList[location-1];
				position = (length - _roomSideLengthList[location-1]) / temp * (temp - furWidth) + furWidth/2;
			}
			else
			{
				position = length / _roomSideLengthList[0] * (_roomSideLengthList[0] - furWidth) + furWidth/2;
			}
			
			furnitureLocation.x = position*tempV.x/tempV.length + _roomPoints[location].x + (furLength/2+1+RoomParameters.wallWidth) * _roomWallVerticalOrentationList[location].x - _room.x;
			furnitureLocation.y = position*tempV.y/tempV.length + _roomPoints[location].y + (furLength/2+1+RoomParameters.wallWidth) * _roomWallVerticalOrentationList[location].y - _room.y;
			
			return new Vector3D(furnitureLocation.x, furnitureLocation.y, _orientedSelectionList[location]);
			
			function binarySearch(rangeA:int, rangeB:int, length:Number):int
			{
				if(rangeA == rangeB)
					return rangeA;	
				var L:int = Math.floor((rangeA + rangeB)/2);
				if(_roomSideLengthList[L] < length)
					return binarySearch(L+1,rangeB,length);
				else if(_roomSideLengthList[L] > length)
					return binarySearch(rangeA,L,length);
				else 
					return L;	
			}
		}
	}
}